﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;

namespace System.Windows.Media.DirectShow
{
    public class MemAllocator : IMemAllocator
    {

        private Queue<MediaSample> samples = new Queue<MediaSample>();
        private bool init;
        private ManualResetEvent sampleEvent = new ManualResetEvent(false);
        private AllocatorProperties _properties;

        public MemAllocator()
        {

        }

        #region IMemAllocator Members

        public AllocatorProperties Properties
        {
            get
            {
                return _properties;
            }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();
                _properties = value;
            }
        }

        public void Commit()
        {
            lock (this)
            {
                if (init) return;

                if (Properties == null)
                    throw new InvalidOperationException("No allocator properties are specified");

                samples.Clear();
                for (int x = 0; x < Properties.BuffersCount; x++)
                    AddNewSample();

                init = true;
            }
        }

        private void AddNewSample()
        {
            samples.Enqueue(new MediaSample(this));
        }

        public void Decommit()
        {
            lock (this)
            {
                samples.Clear();
                init = false;
                sampleEvent.Set();
            }
        }

        public IMediaSample GetBuffer(TimeSpan startTime, TimeSpan endTime)
        {
            lock (this)
            {
                if (!init)
                    return null;
            }
            MediaSample sample = null;
            while (sample == null)
            {
                while (true)
                {
                    int c;
                    lock (this)
                    {
                        c = samples.Count;
                    }
                    if (!init) return null;
                    else if (c == 0)
                        sampleEvent.WaitOne();
                    else
                        break;
                }
                lock (this)
                {
                    sampleEvent.Reset();

                    sample = samples.Dequeue();
                }
                // Ensure buffer are initialized
                if (sample.Data == null)
                {
                    sample.Length = this.Properties.BufferSize;
                    sample.InitData();
                }
            }

            sample.StartTime = startTime;
            sample.EndTime = endTime;

            return sample;
        }

        public void ReleaseBuffer(IMediaSample sample)
        {
            lock (this)
            {
                if (!init)
                    return;
                samples.Enqueue(sample as MediaSample);

                sampleEvent.Set();
            }
        }

        #endregion

    }
}
